import java.awt.*;
import java.util.Random;

/**
 * Created with IntelliJ IDEA.
 * User: Marcin
 * Date: 03.05.13
 * Time: 20:29
 * To change this template use File | Settings | File Templates.
 */
public class Particle implements Comparable<Particle> {

    private static double DEFAULT_WEIGHT = 0.001;

    private double weight;

    private double rotation;

    private int x;

    private int y;

    public Particle() {
        Random random = new Random();
        this.weight = DEFAULT_WEIGHT;
        this.rotation = (random.nextDouble() % 1.0) * 2 * Math.PI;
        this.x = random.nextInt(800);
        this.y = random.nextInt(800);
    }

    public Particle(double weight, double rotation, int x, int y) {
        this.weight = weight;
        this.rotation = rotation;
        this.x = x;
        this.y = y;
    }

    public double getWeight() {
        return weight;
    }

    public void setWeight(double weight) {
        this.weight = weight;
    }

    public double getRotation() {
        return rotation;
    }

    public void setRotation(double rotation) {
        this.rotation = rotation;
    }

    public int getX() {
        return x;
    }

    public void setX(int x) {
        this.x = x;
    }

    public int getY() {
        return y;
    }

    public void setY(int y) {
        this.y = y;
    }

    public Particle getCopyOfMe() {
        return new Particle(getWeight(), getRotation(), getX(), getY());

    }


    public Point moveWithNoise(Direction direction, Map map, double moveNoiseParam) {
        //UWAGA!!!! moveNoiseParam jest w zakresie <0,01 - 1>
        //TODO poprawic aby czasteczki nie wchodzili na sciany i poza plansze

        Random r = new Random();
        setRotation(getRotation() + (r.nextGaussian() * 0.5));
        if (direction == Direction.FORWARD) {
            int newPosX = getX() + (int) (Math.cos(rotation) * Map.STEP_SIZE);
            int newPosY = getY() + (int) (Math.sin(rotation) * Map.STEP_SIZE);
            //TODO dodac szum do ruchu dla x i y
            int param = (int) (moveNoiseParam * 100);
            newPosX += (int) (r.nextGaussian() * param);
            newPosY += (int) (r.nextGaussian() * param);
            Point point = map.getPointOfNearestObject(getX(), getY(), rotation);
            double newPosDistance = map.calculateDistance(getX(), getY(), newPosX, newPosY);
            double nearestWallDistance = map.calculateDistance(getX(), getY(), point.x, point.y);
            if (nearestWallDistance < newPosDistance + 10) {
                newPosX = getX() + (int) (Math.cos(rotation) * (Math.abs(getX() - point.x) - 10));
                newPosY = getY() + (int) (Math.sin(rotation) * (Math.abs(getY() - point.y) - 10));
            }

            //TODO wypadały poza plansze wiec dalem takie ograniczenie lepiej to poprawic aby nie wchodzily na sciany i poza plansze
            if (newPosX > 0 && newPosY > 0 && newPosX < 800 && newPosY < 800) {
                if (!map.isWall(newPosX, newPosY)) {
                    setX(newPosX);
                    setY(newPosY);
                }
            }


        } else {
            int newPosX = getX() - (int) (Math.cos(rotation) * Map.STEP_SIZE);
            int newPosY = getY() - (int) (Math.sin(rotation) * Map.STEP_SIZE);
            //TODO dodac szum do ruchu dla x i y
            int param = (int) (moveNoiseParam * 100);
            newPosX += (int) (r.nextGaussian() * param);
            newPosY += (int) (r.nextGaussian() * param);
            Point point = map.getPointOfNearestObject(getX(), getY(), Math.PI + rotation);
            double newPosDistance = map.calculateDistance(getX(), getY(), newPosX, newPosY);
            double nearestWallDistance = map.calculateDistance(getX(), getY(), point.x, point.y);
            if (nearestWallDistance < newPosDistance + 10) {
                newPosX = getX() - (int) (Math.cos(rotation) * (Math.abs(getX() - point.x) - 10));
                newPosY = getY() - (int) (Math.sin(rotation) * (Math.abs(getY() - point.y) - 10));
            }

            //TODO wypadały poza plansze wiec dalem takie ograniczenie lepiej to poprawic aby nie wchodzily na sciany i poza plansze
            if (newPosX > 0 && newPosY > 0 && newPosX < 800 && newPosY < 800) {
                if (!map.isWall(newPosX, newPosY)) {
                    setX(newPosX);
                    setY(newPosY);
                }
            }
        }
        return new Point(getX(), getY());

    }

    @Override
    public int compareTo(Particle o) {
        Double compareWeight = ((Particle) o).getWeight();
        Double myWeight = getWeight();
        return compareWeight.compareTo(myWeight);
    }
}
